"""
1 交叉验证
在交叉验证中，我们将训练数据生成多个小的训练测试分割，使用这些拆分来调整您的模型。例如，在标准的 k 折交叉验证中，我们将数据划分为 k 个子集。
然后，我们在 k-1 个子集上迭代训练算法，同时使用剩余的子集作为测试集。

将拿到的训练数据分为训练集和验证集。25%为验证集，75为训练集，那就是把数据分成4份，
进行4次训练，每次训练都打乱数据，取其中一份为验证集进行4次训练，就能得到4组的模型结果，
然后取平均值

好处：
在数据有限的情况下，交叉验证充分利用了所有可用样本，通过同时使用所有数据进行训练和评估，提供了对模型性能更可靠的评估。最大化了数据的利用率。
通过在不同的数据子集上进行训练和测试，可以更全面地评估模型的性能。这有助于检测模型对于不同数据分布、特征组合或噪声的鲁棒性。
所有数据都会参与到训练和预测中，有效避免过拟合，充分体现了交叉的思想

2 网格搜索
在有些情况下，有些算法的参数需要手动指定（比如k-近邻算法中的k值），这种叫超参数。
但是我们如果想要选择一个最优的参数组合，就只能手动使用多组参数（k值[1,3,5,7,10]），循环进行训练，
最后根据模型评估的结果选择出效果最好的参数组合（k值2）。而网格搜索就帮我们做了这件事，我们只需输入多组参数，它能自动循环进行训练。


3 交叉验证 + 网格搜索
每组超参数都采用交叉验证来进行评估，最后选出最优参数组合建立模型。
"""

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import GridSearchCV


def knn_iris_gscv():
    """
    k-近邻算法对莺尾花进行分类 加入 交叉验证 和 网格搜索

    estimator = GridSearchCV(estimator, param_grid=param_grid, cv=10)
    estimator算法估计器，param_grid网格搜索超参数，cv交叉验证折数(循环训练次数)

    :return:
    """
    # 1获取数据集
    iris = load_iris()

    # 2数据集划分 random_state随机数种子，不同数据划分也不同
    x_train, x_test, y_train, y_test = train_test_split(iris.data, iris.target, random_state=2)

    # 3特征工程 特征预处理标准化
    transfor = StandardScaler()
    x_train = transfor.fit_transform(x_train)
    x_test = transfor.transform(x_test)

    # 4算法训练 -模型
    estimator = KNeighborsClassifier()
    # 加入交叉验证和网格搜索
    param_grid = {"n_neighbors": [2, 4, 6, 8, 10, 12]}
    estimator = GridSearchCV(estimator, param_grid=param_grid, cv=10)
    estimator.fit(x_train,y_train)

    # 5模型评估
    y_predict = estimator.predict(x_test)
    print("预测值：\n", y_predict)
    print("实际值：\n", y_test)
    print("模型评估方法1，直接比较预测值和实际值：\n", y_predict == y_test)
    print("模型评估方法2，计算模型准确率：\n", estimator.score(x_test,y_test))

    # 最佳参数：best_params_
    print("最佳参数：\n", estimator.best_params_)
    # 最佳结果：best_score_
    print("最佳结果：\n", estimator.best_score_)
    # 最佳估计器：best_estimator_
    print("最佳估计器:\n", estimator.best_estimator_)
    # 交叉验证结果：cv_results_
    print("交叉验证结果:\n", estimator.cv_results_)
    return None

if __name__ == '__main__':
    knn_iris_gscv()